using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Fated.SaveEngine;
using Fated.Character.ChartGeneration;

namespace Fated.Character {
    public class Chart : IJSON {
        public enum Stats { Health, Magic, Body, Mind, Spirit, Social, Speed };
        DateTime birthdate;
        bool yang;
        float[] stats;
        double[] planets;

        List<Aspect> aspects;

        public Chart() {
            stats = new float[] { 50, 50, 20, 20, 20, 20, 0 };
            planets = new double[11];
            aspects = new List<Aspect>();

            Random r = new Random();
            yang = (r.NextDouble() > .5);
        }
        public Chart(DateTime d, bool yang)
            : this() {
            this.yang = yang;
            setBirthdate(d);
        }
        public Chart(Dictionary<String, Object> jsonData) :
            this() {
            this.yang = bool.Parse((String)jsonData["yang"]);
            setBirthdate(DateTime.Parse((String)jsonData["birthdate"]));
        }
        private void addToStat(int[] s, float[] f) {
            for (int i = 0; (i < s.Length && i < f.Length); i++)
                this.stats[s[i]] += f[i];
        }
        public void setBirthdate(DateTime d) {
            stats = new float[] { 50, 50, 20, 20, 20, 20, 0 };
            planets = new double[11];
            aspects.Clear();

            birthdate = d;
            Sun.clear();
            Pluto.clear();
            Planet.yang = this.yang;

            ChartGen.generateChart(birthdate, planets);

            for (var i = 0; i < (int)Planet.PlanetNames.Ascendant; i++) {
                double currentAngle = planets[i];

                for (var j = i + 1; j < (int)Planet.PlanetNames.Ascendant; j++) {
                    double nextAngle = planets[j];

                    double diff = Math.Abs(currentAngle - nextAngle);
                    if (diff + 4 > 120 && diff - 4 < 120) aspects.Add(new Aspect(i, j, Aspect.AspectType.Trine));
                    else if (diff + 4 > 60 && diff - 4 < 60) aspects.Add(new Aspect(i, j, Aspect.AspectType.Sextile));
                    else if (diff + 10 > 0 && diff - 10 < 0) aspects.Add(new Aspect(i, j, Aspect.AspectType.Conjunct));
                    else if (diff + 7 > 180 && diff - 7 < 180) aspects.Add(new Aspect(i, j, Aspect.AspectType.Opposite));
                    else if (diff + 5 > 90 && diff - 5 < 90) aspects.Add(new Aspect(i, j, Aspect.AspectType.Square));
                }
            }
            foreach (Aspect a in aspects) {
                if (a.getPlanet2() == Planet.PlanetNames.Pluto)
                    Pluto.addAspect(a.getPlanet1(), a.getAspect());
                else if (a.getPlanet1() == Planet.PlanetNames.Sun)
                    Sun.addAspect(a.getPlanet2(), a.getAspect());
                else if (a.getAmounts() != null && a.getStats() != null)
                    addToStat(a.getStats(), a.getAmounts());
            }
            int[] f;
            float[] s;
            Sun.getStats(out s, out f);
            addToStat(f, s);
            Pluto.getStats(ref this.stats);

            this.stats[(int)Stats.Speed] = (this.stats[(int)Stats.Body] + this.stats[(int)Stats.Mind]) / 2;
            this.stats[(int)Stats.Health] = (this.stats[(int)Stats.Body] + this.stats[(int)Stats.Spirit]);
            this.stats[(int)Stats.Magic] = (this.stats[(int)Stats.Mind] + this.stats[(int)Stats.Spirit]);

        }

        public DateTime getBirthdate() {
            return birthdate;
        }

        public string printAspects() {
            string output = "";
            foreach (Aspect a in aspects) {
                output += a.getPlanet1() + " " + a.getAspect() + " " + a.getPlanet2() + "\r\n";
            }
            return output;
        }

        public Dictionary<string, object> ToJSON() {
            Dictionary<string, object> output = new Dictionary<string, object>();
            output.Add("yang", this.yang.ToString());
            output.Add("birthdate", this.birthdate.ToString());
            
            return output;
        }

        #region Getters/Setters
        public int Health {
            get { return (int)stats[(int)Stats.Health]; }
        }
        public int Magic {
            get { return (int)stats[(int)Stats.Magic]; }
        }
        public int Body {
            get { return (int)stats[(int)Stats.Body]; }
        }
        public int Mind {
            get { return (int)stats[(int)Stats.Mind]; }
        }
        public int Spirit {
            get { return (int)stats[(int)Stats.Spirit]; }
        }
        public int Social {
            get { return (int)stats[(int)Stats.Social]; }
        }
        public int Speed {
            get { return (int)stats[(int)Stats.Speed]; }
        }
        #endregion
    }
}
